﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Collections;

/// <summary>
/// Summary description for SimpleJSON
/// </summary>
public class SimpleJSON
{
	private Dictionary<string,object> values = new Dictionary<string,object>();

    public bool IsArray { get; private set; }

    public SimpleJSON Set(string name, object value)
    {
        values[name] = value;
        return this;
    }

    public SimpleJSON Set(string name, Action<SimpleJSON> code)
    {
        var o = new SimpleJSON();
        code(o);
        values[name] = o;
        return this;
    }

    public object this[string name]
    {
        get { return values[name]; }
        set 
        {
            IsArray = false;
            values[name] = value;
        }
    }

    public string Serialize()
    {
        StringBuilder buffer = new StringBuilder();
        WriteJSON(this, buffer);
        return buffer.ToString();
    }

    public override string ToString()
    {
        return Serialize();
    }

    public static SimpleJSON Create(object data)
    {
        SimpleJSON ret = new SimpleJSON();
        if (data == null)
        {
            return null;
        }
        if (data is ValueType || data is string)
        {
            return new SimpleJSON().Set("data", data);
        }

        if (data is IDictionary)
        {
            return FillFromDictionary(data as IDictionary);
        }
        if (data is IEnumerable)
        {
            return FillFromEnumerable(data as IEnumerable);
        }
        foreach (var p in data.GetType().GetProperties())
        {
            var obj = p.GetValue(data, null);
            ret[p.Name] = MakeValueOrJSON(obj);
        }
        return ret;
    }

    public static object MakeValueOrJSON(object value)
    {
        if (value == null)
        {
            return null;
        }
        if (value is ValueType || value is string)
        {
            return value;
        }
        if (value is IDictionary)
        {
            return FillFromDictionary(value as IDictionary);
        }
        if (value is IEnumerable)
        {
            return FillFromEnumerable(value as IEnumerable);
        }
        return Create(value);
    }
 
    public static SimpleJSON FillFromDictionary(IDictionary data)
    {
        SimpleJSON ret = new SimpleJSON(); 
        foreach (var key in (data as IDictionary).Keys)
        {
            ret[key.ToString()] = MakeValueOrJSON(data[key]);
        }
        return ret;
    }

    public static SimpleJSON FillFromEnumerable(IEnumerable data)
    {
        SimpleJSON result = new SimpleJSON();
        int index = 0;
        foreach (var item in data)
        {
            result[(index).ToString()] = MakeValueOrJSON(item);
            index++;
        }
        result.IsArray = true;
        return result;
    }

    private static void WriteJSON(SimpleJSON simpleJSON, StringBuilder buffer)
    {
        if (simpleJSON.IsArray)
        {
            buffer.Append("[");
        }
        else
            buffer.Append("{");
        bool first = true;
        foreach(var pair in simpleJSON.values)
        {
            if (first)
            {
                first = false;
            }
            else
                buffer.Append(",");
            if (!simpleJSON.IsArray)
            {
                AppendNameOrValue(buffer, pair.Key);
                buffer.Append(":");
            }
            if (pair.Value == null)
            {
                buffer.Append("null ");
                continue;
            }
            if (pair.Value is SimpleJSON)
            {
                WriteJSON(pair.Value as SimpleJSON, buffer);
            }
            else
            {
                AppendNameOrValue(buffer, pair.Value);
            }
        }
        if (simpleJSON.IsArray)
        {
            buffer.Append("]");
        }
        else
            buffer.Append("}");
    }

    private static void AppendNameOrValue(StringBuilder buffer, object p)
    {
        buffer.Append("\"").Append(p == null 
            ? "null " 
            : p.ToString().Replace("\\","\\\\")
                .Replace("\"", "\\\"")
                .Replace("\t","\\t")
                .Replace("\r", "\\r")
                .Replace("\n", "\\n")
                .Replace("'", "\\'")
        ).Append("\"");
    }

        
}